package AnalisadorLexico;

import Principal.Erro;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeMap;

/**
 *
 * @author Fábio Novais
 */
public class Principal
{

    private static File _arquivoTemporario;
    private static FileWriter _fw;
    private static BufferedWriter _bw;
    private static TreeMap<Integer, String> _comentariosDocomment =
            new TreeMap<Integer, String>();

    public static void main(String args[]) throws FileNotFoundException, IOException
    {
        if (args.length <= 0)
        {
            System.out.println("Nome de arquivo faltando");
            return;
        }

        String codigoFonte = args[0];

        IniciarArquivosTemporario();

        if (codigoFonte.length() <= 0)
        {
            return;
        }

        try
        {
            BufferedReader bf = AbrirArquivo(codigoFonte);
            RealizarPreProcessamento(bf);
            bf.close();
            bf = AbrirArquivo("doComment.dom");
            TreeMap<String, ArrayList<String>> tokens = RetornarListaTokens(bf);
            bf.close();

            Iterator iteratorKeySet = tokens.keySet().iterator();

            while (iteratorKeySet.hasNext())
            {
                String key = (String) iteratorKeySet.next();
                ArrayList<String> valores = tokens.get(key);

                Iterator iteratorValores = valores.iterator();
                while (iteratorValores.hasNext())
                {
                    String valor = (String) iteratorValores.next();
                    if (key.equals(Token.getNOMATCH()))
                    {
                        System.out.println(key + ";" + valor);
                    } else
                    {
                        System.out.println(valor + ";" + key);
                    }
                }
            }

            if (TratadorErros.getListasObjetosErro().size() <= 0)
            {
                AnalisadorSintatico.Analisador analisadorSintatico = new AnalisadorSintatico.Analisador();
                analisadorSintatico.Analisar();
            } else
            {
                ImprimirErros();
            }

        } catch (Exception ex)
        {
            System.out.println("Erro: " + ex.getStackTrace().toString());
        }
    }

    /**
     * Abre um arquivo para leitura
     * @param caminho do arquivo
     * @return Buffer do arquivo
     * @throws FileNotFoundException
     * @throws IOException
     */
    public static BufferedReader AbrirArquivo(String caminho) throws FileNotFoundException, IOException
    {
        FileReader fr = new FileReader(caminho);

        BufferedReader bf = new BufferedReader(fr);

        return bf;
    }

    /**
     * Transfere as linhas relevantes do código fonte para um arquivo temporário
     * @param Código original em ruby
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static void RealizarPreProcessamento(BufferedReader codigoFonte) throws FileNotFoundException, IOException
    {
        String linha;
        Analisador analisador = new Analisador();
        TreeMap<Integer, String> comentariosDoComment = new TreeMap<Integer, String>();

        Integer numLinha = 0;

        while ((linha = codigoFonte.readLine()) != null)
        {
            numLinha++;
            if (linha.trim().startsWith("#")) //Verifica se é um comentário
            {
                comentariosDoComment.put(numLinha, linha.trim());
            } else
            {
                if (analisador.IsDefClass(linha) //Se não for comentário verifica se é classe ou método
                        || analisador.IsDefMethod(linha))
                {
                    if (comentariosDoComment.size() >= 1)
                    {
                        String linhaAnterior = comentariosDoComment.get(numLinha - 1);
                        if (linhaAnterior.startsWith("#")) //Verifica se o anterior foi comentário
                        {
                            comentariosDoComment.put(numLinha, linha.trim());
                            GravarArquivoTemporario(comentariosDoComment);
                            comentariosDoComment.clear();
                        }
                    }
                }
            }
        }

        _fw.close();
    }

    /**
     * Analisa o arquivo temporário para trazer uma lista de tokens casados
     * @param arquivo temporário
     * @return Árvore com tokens casados com seus respectivos padrões
     * @throws IOException
     */
    private static TreeMap<String, ArrayList<String>> RetornarListaTokens(BufferedReader arquivoTemporario) throws IOException, Exception
    {
        String linha;
        Analisador analisador = new Analisador();

        try
        {
            while ((linha = arquivoTemporario.readLine()) != null)
            {
                analisador.Analisar(linha);
            }
        } catch (Exception ex)
        {
            throw new Exception("Erro inesperado da aplicação.");
        }

        return analisador.getTokens();
    }

    /**
     * Grava informações no arquivo temporário
     * @param Lista de códigos DoComment
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static void GravarArquivoTemporario(TreeMap<Integer, String> comentariosDoComment) throws FileNotFoundException, IOException
    {
        Iterator iterator = comentariosDoComment.keySet().iterator();
        while (iterator.hasNext())
        {
            int numLinha = Integer.parseInt(iterator.next().toString());
            String linha = comentariosDoComment.get(numLinha);
            _fw.write(numLinha + "%%" + " " + linha + " ");
            _fw.write(System.getProperty("line.separator"));
        }
    }

    /**
     * Inicia os arquivos temporários
     * @throws IOException
     */
    private static void IniciarArquivosTemporario() throws IOException
    {
        if (_arquivoTemporario == null)
        {
            _arquivoTemporario = new File("doComment.dom");
        }

        if (_fw == null)
        {
            _fw = new FileWriter(_arquivoTemporario);
        }
        if (_bw == null)
        {
            _bw = new BufferedWriter(_fw);
        }
    }

    /**
     * Imprime os erros do analisador lexico.
     */
    private static void ImprimirErros()
    {
        Iterator iterator = TratadorErros.getListasObjetosErro().iterator();
        while (iterator.hasNext())
        {
            Erro erro = (Erro) iterator.next();
            System.out.println("Erro linha número " + erro.getNumLinha());
            System.out.println("\tCódigo do erro: " + erro.getCodErro());
            System.out.println("\tDescrição: " + erro.getMensagemErro());
            System.out.println("\tSequência: " + erro.getSequencia());
        }
    }
}
